/*
		ServEngine framework library
		A library to fast develop JEE online applications
	
		Copyright 2008 José Ignacio de Córdoba Álvaro

		Licensed under the Apache License, Version 2.0 (the "License");
		you may not use this file except in compliance with the License.
		You may obtain a copy of the License at

				http://www.apache.org/licenses/LICENSE-2.0

		Unless required by applicable law or agreed to in writing, software
		distributed under the License is distributed on an "AS IS" BASIS,
		WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
		See the License for the specific language governing permissions and
		limitations under the License.
	
		Jose Ignacio de Cordoba Alvaro
		http://ignacio.decordoba.com
*/

package com.servengine.util;

import com.servengine.Cleaner;

import com.servengine.entry.EntryManagerLocal;

import java.awt.GraphicsEnvironment;

import javax.servlet.*;

import com.servengine.user.*;
import com.servengine.portal.*;
import com.servengine.struts.AuthorizeAction;

import java.util.*;

import javax.servlet.http.*;

import java.io.*;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

import javax.security.auth.login.FailedLoginException;

import org.apache.commons.lang.StringUtils;

public class ServletContextUtils extends com.servengine.ServletContextClient implements HttpSessionListener //,HttpSessionAttributeListener
{
	private static org.apache.commons.logging.Log log=org.apache.commons.logging.LogFactory.getLog(ServletContextUtils.class.getName());
	public static String TIMER_JNDINAME_INIT_PARAMETER_ID="timer.jndinames"; // Comma separated EJB Timer jndi names
	public static String TIMER_INIT_PARAMETER_ID_PREFIX="timer."; // Comma separated EJB Timer jndi names
	public static String MAIN_PORTAL_ID="portal.mainportalid";
	public static String GENERIC_PORTAL_ID="portal.genericportalid";
	public static String DEFAULT_LOCALE="portal.defaultlocale";
	public static String PORTAL_COLORS_PROPERTY_NAME="portal.colors";
	public static String PORTAL_CSSURL_PROPERTY_NAME="portal.cssURL";

	public static String SERVLETCONTEXT_ATTRIBUTE_NAME="servletContextUtils"; //ServletContextUtils.class.getName();

	//	public static String ADMIN_USERIDS = "user.adminuserids";

	//	protected HashMap onlineusermanagerclients;
	//	protected HashMap<Integer,UserActionForm> onlineusers;
	private Date initializedDate;
	//	private Languages languages;
	private ServiceIPLimiter serviceiplimiter;
	protected long maxportalspace;
	protected Map<String, PortalSpaceUsed> portalsspaceused;
	//	protected File userpicturesdir;
	protected Map<String, HttpSession> httpSessions;
	protected ExpensiveDataFactory expensiveDataFactory;
	//	protected Map<String,Component> actionsInContextClassPath;
	protected Map<String, Cleaner> cleanersInContextClassPath;
	private String mainportalid, genericportalid;
	private String defaultlocale;
	//	private String globaladminuserids; // No puede moverse de aqui por si estos usuarios no existen todavia

	//	private Map<String,User> guestUsers; //EXPURGANDA

	public void clientInitialized(javax.naming.Context context)
	{
		try
		{
			initializedDate=new Date();
			httpSessions=new HashMap<String, HttpSession>();
			//			languages = new Languages(servletcontext,"errormessages.xml");
			expensiveDataFactory=new ExpensiveDataFactory(usermanager, portalmanager);
			serviceiplimiter=new ServiceIPLimiter();
			portalsspaceused=new HashMap<String, PortalSpaceUsed>();
			log.info("GraphicsEnvironment.isHeadless()="+GraphicsEnvironment.isHeadless());

			/*			String timerJNDINames = servletcontext.getInitParameter(TIMER_JNDINAME_INIT_PARAMETER_ID);
			if (timerJNDINames!=null)
			{
				Map<String,Long> timersinfo = new HashMap<String,Long>();
				for (String timerJNDIName: timerJNDINames.split(","))
					try
					{
						timersinfo.put(timerJNDIName,new Long(servletcontext.getInitParameter(TIMER_INIT_PARAMETER_ID_PREFIX+timerJNDIName+".timeout")));
					} catch (NumberFormatException e)
					{
					  timersinfo.put(timerJNDIName,new Long(180000));
					  log.warn("Default 180000 ms timeout for timer@"+timerJNDIName+" as didn't find "+TIMER_INIT_PARAMETER_ID_PREFIX+timerJNDIName+".timeout context parameter");
//						log.warn("Didn't startup timer@"+timerJNDIName+". Please specify "+TIMER_INIT_PARAMETER_ID_PREFIX+timerJNDIName+".timeout context parameter");
					}
				initializeTimers(initialcontext,timersinfo);
			}
			if (servletcontext.getInitParameter("maxportalspace")==null)
			{
				maxportalspace = 1024*1024*1024; // 1GB por defecto
				servletcontext.log("No maxportalspace init parameter. Defaults to "+maxportalspace);
			} else
			{
				maxportalspace = Long.parseLong(servletcontext.getInitParameter("maxportalspace"));
				servletcontext.log("maxportalspace="+maxportalspace/1024+" KB");
			}*/

			checkActionsAndCleanersInContext();

			//defaultlocale = (String)initial.lookup("java:comp/env/global.defaultlanguageid");
			defaultlocale=servletContext.getInitParameter(DEFAULT_LOCALE);
			if (defaultlocale==null)
			{
				defaultlocale="en"; //¿Mirar el default de la máquina virtual?
				log.warn("No "+DEFAULT_LOCALE+" init parameter. Defaults to: "+defaultlocale);
			}

			mainportalid=servletContext.getInitParameter(MAIN_PORTAL_ID);
			if (mainportalid==null)
			{
				if (StringUtils.isAlphanumeric(servletContext.getServletContextName()))
				{
					mainportalid=servletContext.getServletContextName().toLowerCase();
					log.warn("No mainportalid. Using application name "+mainportalid+" as main portalid");
				} else
					throw new IllegalStateException("ServletContextUtils needs init parameter variable "+MAIN_PORTAL_ID+" or an alphanumeric application name");
			}
			//	    globaladminuserids = servletcontext.getI jnitParameter(ADMIN_USERIDS);
			/*			if (globaladminuserids == null)
			{
			  globaladminuserids = "admin";
			  log.warn("No "+ADMIN_USERIDS+" init parameter. Defaults to: "+globaladminuserids);
			}*/

			log.info("Checking main portal "+mainportalid+"...");
			
			portalmanager.checkPortal(mainportalid, defaultlocale, true);
			
			genericportalid=servletContext.getInitParameter(GENERIC_PORTAL_ID);
			if (genericportalid==null)
			{
				genericportalid="generic";
				log.warn("No "+genericportalid+" init parameter. Defaults to: "+genericportalid);
			}
			portalmanager.checkPortal(genericportalid, defaultlocale, false);

			//			guestUsers = portalmanager.getGuestUsers();

			/*			if (servletcontext.getInitParameter("user.picturesdir")==null)
			{
				String realpath = servletcontext.getRealPath("/");
				if (realpath==null)
					throw new IllegalStateException("Can't init this bean as InitParameter user.picturesdir is not present in web application and can't default to getContext().getRealPath()");
				userpicturesdir = new File(realpath+"/"+"servicesimgs/userpictures/");
				log.warn("No user.picturesdir parameter in webapp. Defaults to "+userpicturesdir);
			} else
				userpicturesdir = new File(servletcontext.getInitParameter("user.picturesdir"));
			if (!userpicturesdir.exists())
				log.warn("Directory "+userpicturesdir+" didn't exist. Creating it: "+userpicturesdir.mkdirs());
			if (userpicturesdir.isFile())
				log.warn("Directory "+userpicturesdir+" is a file, man...");*/
		} catch (RuntimeException e)
		{
			log.error("ServletContextUtils: RuntimeException: ", e);
			throw e;
		} catch (Exception e)
		{
			log.error("ServletContextUtils: Exception: ", e);
			throw new IllegalStateException(e.getMessage());
		}
	}

	public void clientDestroyed()
	{
		Collection<HttpSession> aux=new ArrayList<HttpSession>();
		aux.addAll(httpSessions.values());
		if (httpSessions!=null)
			for (HttpSession session: aux)
				try
				{
					session.invalidate();
				} catch (IllegalStateException e)
				{
					if (log.isDebugEnabled())
						log.debug(e.getMessage());
				}
	}

	public void sessionCreated(HttpSessionEvent se)
	{
		if (log.isDebugEnabled())
			log.debug("New session: "+se.getSession().getId());
		httpSessions.put(se.getSession().getId(), se.getSession());
	}

	public void sessionDestroyed(HttpSessionEvent se)
	{
		try
		{
			UserSession userSession=((UserSessionSBean)se.getSession().getAttribute(AuthorizeAction.USERSESSIONSBEAN_ATTRIBUTEID)).getUserSession();
			if (userSession.getId()!=null)
				usermanager.userUnbound(userSession.getId());
			else
				log.error("Can't mark user session as destroyed. No id: "+userSession.getUserid()+"@"+userSession.getPortalid());
		} catch (NullPointerException e)
		{
			log.error("No "+AuthorizeAction.USERSESSIONSBEAN_ATTRIBUTEID+" session attribute: "+se.getSession().getAttribute(AuthorizeAction.USERSESSIONSBEAN_ATTRIBUTEID));
		}
		httpSessions.remove(se.getSession().getId());
		if (log.isDebugEnabled())
			log.debug("Session destroyed: "+se.getSession().getId());
	}

	/*	private void initializeTimers(javax.naming.InitialContext initialcontext, Map<String,Long> timersinfo ) throws NamingException
	{	  //((MailRelayHome)initialcontext.lookup("MailRelay")).create().initializeTimer(120000,servletcontext.getServletContextName()+" multimail timer");
		for (String jndiname: timersinfo.keySet())
		{
			Object timedObject = initialcontext.lookup(jndiname);
				try
				{
					//java.lang.reflect.Method createmethod = ejbhome.getClass().getMethod("create",new Class[0]);
					//Object timedObject = createmethod.invoke(ejbhome,new Object[0]);
					Object[] timerparameters = new Object[2];
					timerparameters[0] = timersinfo.get(jndiname);
					timerparameters[1] = servletcontext.getServletContextName()+"/"+jndiname.split("/")[0];
					Class[] timerparametersclasses = new Class[2];
					timerparametersclasses[0] = timerparameters[0].getClass();
					timerparametersclasses[1] = timerparameters[1].getClass();
					java.lang.reflect.Method initializeTimerMethod = timedObject.getClass().getMethod("initializeTimer",timerparametersclasses);
					initializeTimerMethod.invoke(timedObject,timerparameters);
				} catch (Exception e)
				{
					log.error(e.getMessage(),e);
				}
		}
	}*/
	/*  private void createManagers() throws NamingException,RemoteException,CreateException,IOException
  {
    Properties read = new Properties();
    String url=null;
    InputStream servicespropstream = context.getResourceAsStream("/WEB-INF/services.prop");
    if (servicespropstream!=null)
    {
      read.load(servicespropstream);
      url = read.getProperty(getClass().getName());
      if (url==null)
        url = read.getProperty("default");
    }
    if (url==null)
    {
      url="jnp://localhost:1099/"+context.getServletContextName();
      context.log("No default url found. Defaults to JBoss url with ServletContextName: "+context.getServletContextName());
      context.log(url);
    }

    if (url==null)
      throw new IllegalStateException("No URL for EJB lookup!!! at "+getClass().getName());

    context.log(getClass().getName()+" setting InitialContext at: "+url);
    java.util.Hashtable props = new java.util.Hashtable();
    props.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
    props.put("java.naming.provider.url", url);
    props.put(javax.naming.Context.URL_PKG_PREFIXES,"org.jboss.naming:org.jnp.interfaces");
    initialcontext = new javax.naming.InitialContext(props);
    statelessutils = ((StatelessUtilsHome)initialcontext.lookup("StatelessUtils")).create();
    portalmanager = ((PortalManagerHome)initialcontext.lookup("PortalManager")).create();
  }*/
	/*    public StatelessUtilsLocal getStatelessUtils()
    {
        return statelessutils;
    }*/

	public PortalManagerLocal getPortalmanager()
	{
		return portalmanager;
	}

	public UserManagerLocal getUserManager()
	{
		return usermanager;
	}

	public EntryManagerLocal getEntryManager()
	{
		return entryManager;
	}

	public Date getInitializedDate()
	{
		return initializedDate;
	}

	public String getMainPortalid()
	{
		return mainportalid;
	}

	/**
	 *@deprecated
	 * @return
	 */
	public String getMainportalid()
	{
		return mainportalid;
	}

	public Portal getPortal(String portalid) throws java.rmi.RemoteException
	{
		Portal portal=portalmanager.getPortal(portalid);
		if (portal==null)
			throw new com.servengine.portal.UnidentifiedPortalException();
		return portal;
	}
	/*
   * Method to be overriden, in tuportal.com for example
   */

	public long getMaxportalspace(String portalid)
	{
		log.warn("Returning ServEngine max portal space for portalid: "+portalid+" ("+maxportalspace+")");
		return maxportalspace;
	}

	private class PortalSpaceUsed
	{
		String portalid;
		long spaceused;
		long timeinmillis;

		PortalSpaceUsed(String portalid, long spaceused)
		{
			this.portalid=portalid;
			this.spaceused=spaceused;
			timeinmillis=new java.util.Date().getTime();
		}

		public String getPortalid()
		{
			return portalid;
		}

		public long getSpaceused()
		{
			return spaceused;
		}

		public long getTimeinmillis()
		{
			return timeinmillis;
		}
	}

	public long getPortalspaceused(String portalid)
	{
		PortalSpaceUsed spaceused=portalsspaceused.get(portalid);
		if (spaceused==null||new Date().getTime()-spaceused.getTimeinmillis()>120000)
		{
			spaceused=new PortalSpaceUsed(portalid, summuppportalspaceused(portalid));
			portalsspaceused.put(portalid, spaceused);
		}
		return spaceused.getSpaceused();
	}

	/*	protected Cleaner getCleaner(ServletContext context, String className) throws ClassNotFoundException,NoSuchMethodException,InstantiationException,IllegalAccessException,InvocationTargetException
	{
	  Class[] constructorclasses=new Class[]{ context.getClass() };
		Object[] constructorparameters = new Object[] { context };
	  return (com.servengine.Cleaner)(Class.forName(className).getConstructor(constructorclasses).newInstance(constructorparameters));
	}*/

	public Collection<Cleaner> getCleaners()
	{
		return cleanersInContextClassPath.values();
	}

	private long summuppportalspaceused(String portalid)
	{
		long portalspaceused=0;
		try
		{
			for (Cleaner cleaner: cleanersInContextClassPath.values())
				try
				{
					long spaceused=cleaner.getSpaceused(portalid);
					portalspaceused+=spaceused;
					if (log.isDebugEnabled())
						log.debug(cleaner.getClass().getName()+"@"+portalid+": "+spaceused/1024+" KB");
				} catch (java.lang.NoClassDefFoundError e)
				{
					log.error("IMPORTANTE: No existe la clase: "+e+"/"+e.getMessage());
				}
		} catch (Throwable e)
		{
			log.error(e.getMessage(), e);
		}
		return portalspaceused;
	}

	public void checkAvailableportalspace(String portalid, long howmuch)
	{
		if (howmuch+getPortalspaceused(portalid)>getMaxportalspace(portalid))
			throw new IllegalArgumentException("Can't user more space in this portal. You are already using "+getPortalspaceused(portalid)/1024+" out of "+getMaxportalspace(portalid)/1024+" KB.");
	}

	/*	public void setCheckrememberedsession(HttpServletRequest request) throws NamingException,RemoteException, FailedLoginException,CreateException,FinderException
	{
	  checkrememberedsession(request);
	}
*/
	/*	public boolean checkrememberedsession(HttpServletRequest request) throws NamingException,RemoteException, FailedLoginException,CreateException,FinderException
	{
		Cookie[] cookies = request.getCookies();
		if (cookies!=null)
		{
			String portalid=request.getParameter("portalid");
			if (portalid==null)
			{
				UserActionForm u = (UserActionForm)request.getSession(true).getAttribute("user");
				if (u!=null)
					portalid = u.getPortal().getId();
			}
			if (portalid==null)
			{
				for (int i=0; i<cookies.length; i++)
				if (cookies[i].getName().equals("portalid") && cookies[i].getValue()!=null && cookies[i].getValue().length()>0)
					portalid=cookies[i].getValue();
			}
			if (portalid==null)
				return false;
		}
		return false;
	}*/

	/**
	 * @deprecated
	 * Comprueba si alguna de las sesiones recordadas es de administración, y hace el autologin en su caso
	 */
	public boolean checkrememberedadminsession(HttpServletRequest request) throws FailedLoginException
	{
		Cookie[] cookies=request.getCookies();
		if (cookies!=null)
		{
			for (int i=0;i<cookies.length;i++)
			{
				if (cookies[i].getName().indexOf("servengineautologin#")==0&&cookies[i].getValue()!=null&&cookies[i].getValue().length()>0)
				{
					User user=usermanager.getUserBySession(new Integer(cookies[i].getValue()));
					if (user==null)
						return false;
					String portalid=cookies[i].getName().substring(20); // Por seguridad, comprobamos el portalid.
					if (user.getPortalid().equals(portalid)&&usermanager.isAdmin(user))
						;
					{
						request.getSession(true).setAttribute("user", user);
						return true;
					}
				}
			}
		}
		return false;
	}
	/*	public UserSBean removerememberedsession(HttpSession session, HttpServletResponse res)
	{
		UserSBean user = (UserSBean)session.getAttribute("user");
		if (user==null)
			return null;
		Cookie cookie = new Cookie("servengineautologin#"+user.getPortalid(),"");
		cookie.setMaxAge(0); // Con esto se borra la cookie.
		 cookie.setPath("/");
		res.addCookie(cookie);
		return usermanager.getGuestUserSession());
	}*/
	/*	public boolean checkUserpassword(String portalid, String userid, String password) throws RemoteException,CreateException
	{
		try
		{
			usermanager.getUser(portalid,userid,password);
			return true;
		} catch (javax.security.auth.login.FailedLoginException e) {return false;}
		catch (java.rmi.AccessException e) { return false; }
	}*/
	/*	public boolean checkUserpassword(String user, String password) throws RemoteException,CreateException
	{
		int index=user.lastIndexOf("_");
		if (index<1)
		{
			index=user.lastIndexOf("@");
			if (index<1)
				return false;
		}
		String userid=user.substring(0,index);
		String portalid=user.substring(index+1);
		return checkUserpassword(portalid,userid,password);
	}*/
	/*	public void validate(String portalid, String userid, String password, HttpSession session) throws NamingException,CreateException,javax.security.auth.login.FailedLoginException,RemoteException,ClassNotFoundException
	{
	  log.warn("Deprecated call to validate()");
		validate(portalid,userid,password,session, null,false);
	}*/
	/*	public void validate(String portalid, String userid, String password,HttpSession session, HttpServletResponse res,boolean remembersession) throws NamingException,CreateException,javax.security.auth.login.FailedLoginException,RemoteException,ClassNotFoundException
	{
		log.warn("Deprecated call to validate()");
		if (true)
			return;
	
	  res.addHeader("P3P","CP=\"CAO PSA OUR\"");
		try
		{
			UserSBean user = usermanager.getUser(portalid,userid,password);
			session.setAttribute("user",user);
			UserManagerClient usermanagerclient = new UserManagerClient();
			session.setAttribute("usermanager",usermanagerclient);
			usermanagerclient.setPortalid(portalid);
			if (res!=null)
			{
				Cookie cookie = new Cookie("portalid",portalid);
				cookie.setMaxAge(7*60*60*24); // Siete d%%as.
				cookie.setPath("/");
				res.addCookie(cookie);
				int days = usermanager.getSessionrememberdays(portalid);
                if (remembersession) session.setAttribute("remembersession","true");
				else session.removeAttribute("remembersession");
                if (days>0 && remembersession)
				{
					cookie = new Cookie("servengineautologin#"+portalid,user.getUserSession().getPkey().toString());
					cookie.setMaxAge(days*60*60*24);
					cookie.setPath("/");
					res.addCookie(cookie);
					if (log.isDebugEnabled()) log.debug(cookie.getName()+"="+cookie.getValue());
				}
			}
			removeClients(session, null); //Quitamos los otros clientes, que han sido instanciados bajo otro portalid. Pasamos null por que no estamos en un ManagerJSPClient
			session.getServletContext().log("ServletContextUtils.validate(): "+user.getUserid()+"@"+user.getPortalid());
		} catch (RemoteException e)
		{
			if (e.getCause()==null)
      {
        servletcontext.log(e.getMessage(),e);
				throw new IllegalStateException(e.getMessage()+"/"+e);
      }
			else
				throw e;
		}
		catch (RuntimeException e)
		{
			servletcontext.log(e.getMessage(),e);
			session.removeAttribute("user@"+portalid);
			session.getServletContext().log("ServletContextUtils.validate(): "+e+" ("+e.getMessage()+"), "+userid+"/"+portalid);
			throw new javax.security.auth.login.FailedLoginException(e+": "+e.getMessage());
		} catch (FinderException e)
		{
			session.removeAttribute("user@"+portalid);
			session.getServletContext().log("ServletContextUtils.validate(): "+e+" ("+e.getMessage()+"), "+userid+"/"+portalid);
			throw new javax.security.auth.login.FailedLoginException(e+": "+e.getMessage());
		}
	}*/

	/**
	 * Este metodo es invocado desde checkportal() y desde ServletContextUtils.validate(). Pasando null quita todos los clientes (ojo!!)
	 */
	public void removeClients(HttpSession session, Class butthis) throws ClassNotFoundException
	{
		Class managerjspclientbeanclass=Class.forName("com.servengine.ManagerJSPClientBean");
		Enumeration e=session.getAttributeNames();
		while (e.hasMoreElements())
		{
			String name=(String)e.nextElement();
			Object cliente=session.getAttribute(name);
			if (managerjspclientbeanclass.isInstance(cliente)) //Sacamos todos los clientes de la sesi%%n menos este objeto, que lo acabamos de introducir.
				if (butthis==null||!cliente.getClass().equals(butthis.getClass()))
					session.removeAttribute(name);
		}
	}
	/*	public void sendconfirmchangepassword(String portalid, String userid) throws FinderException, RemoteException
	{
		usermanager.sendPasswordchangerequest(portalid,userid);
	}
	public void sendpassword(String portalid, String userid,String authcode) throws InvalidKeyException, FinderException, RemoteException
	{
    usermanager.sendNewpassword(portalid,userid,authcode);
	}

	public Integer createUser(String portalid, String userid, String[] password, String firstname, String lastname, String lastname2, String email) throws NamingException,CreateException,javax.security.auth.login.FailedLoginException,RemoteException,FinderException,RemoveException
	{
		return createUser(portalid,userid,password,firstname,lastname,lastname2,email,null);
	}
	public Integer createUser(String portalid, String userid, String[] password, String firstname, String lastname, String lastname2, String email, Map requestextrauserdata) throws NamingException,CreateException,javax.security.auth.login.FailedLoginException,RemoteException,FinderException,RemoveException
	{
		if (!userid.equals("guest"))
		{
			if (password==null || password.length<1 || password.length>2 || password[0] == null)
				throw new IllegalArgumentException("Must supply one or two values for password");
			if (password.length==2 && !password[0].equals(password[1]))
				throw new IllegalArgumentException("Passwords don't match");
		} else
			password = new String[0]; // En el caso de usuario invitado.
		if (!getPortal(portalid).isUserautoregistering())
			throw new CreateException("Only admin can create users in this portal");
		UserSBean user = new UserSBean(this.getPortal(portalid),null,userid);
		user.setNewpassword(password[0]);
		user.setFirstname(firstname);
		user.setLastname(lastname);
		user.setLastname2(lastname2);
		user.setEmail(email);
		user.setRolepkeys(usermanager.getNewuserrolepkeys(portalid));
		
		if (requestextrauserdata!=null && requestextrauserdata.size()>0)
		{
			Collection extrauserdata = new ArrayList();
			Iterator it = usermanager.getExtrauserdatafields(portalid).iterator();
			while (it.hasNext())
			{
				ExtraUserdataFieldSBean field = (ExtraUserdataFieldSBean)it.next();
				if (requestextrauserdata.containsKey(field.getName()) && ((String[])requestextrauserdata.get(field.getName()))[0].length()>0)
					extrauserdata.add(new ExtraUserdataSBean(field,((String[])requestextrauserdata.get(field.getName()))[0]));
				else if (field.getRequired())
					throw new IllegalArgumentException("Required extra user data field "+field.getName()+" not supplied.");
			}
			user.setExtrauserdata(extrauserdata);
		}
		return statelessutils.storeUser(user,true);
	}*/

	public void removeUsers(String portalid, String[] ids)
	{
		for (int i=0;i<ids.length;i++)
		{
			usermanager.removeUser(portalid, ids[i]);
			for (Cleaner cleaner: cleanersInContextClassPath.values())
				cleaner.userRemoved(portalid, ids[i]);
		}
	}
	/*	public void userUnbound(Integer usersessionpkey) throws RemoteException,FinderException
	{
		usermanager.userUnbound(usersessionpkey);
		onlineusermanagerclients.remove(usersessionpkey);
	}*/
	/*	public void bindUsermanagerclient(Integer usersessionpkey, UserManagerClient usermanagerclient)
	{
		onlineusermanagerclients.put(usersessionpkey,usermanagerclient);
	}
	public void unbindUsermanagerclient(Integer usersessionpkey)
	{
		onlineusermanagerclients.remove(usersessionpkey);
	}
*/
	/*	public void attributeAdded(HttpSessionBindingEvent se)
	{
	}

	public void attributeRemoved(HttpSessionBindingEvent se)
	{
	  try
	  {
	    if (se.getName().equals("userSession") && ((UserSessionSBean)se.getValue()).getPkey()!=null)
	      ((UserSessionSBean)se.getValue()).attributeRemoved();;
	  } catch (Exception e)
	  {
	    log.error(e.getMessage(),e);
	  }
	}

	public void attributeReplaced(HttpSessionBindingEvent se)
	{
	}*/

	/**
	 * Para la desconexión de usuarios de un portal. Comprueba que la sesión es de un usuario del portal en cuestión.
	 */
	public String disconnectSession(String portalid, String sessionid)
	{
		HttpSession session=httpSessions.get(sessionid);
		UserSessionSBean userSession=(UserSessionSBean)session.getAttribute("userSession");
		if (!userSession.getPortalid().equals(portalid))
			throw new IllegalArgumentException("Ufff... my friend. That online user doesn't seem to belong to your portal");
		session.invalidate();
		log.info("User session "+userSession.getUserid()+"@"+userSession.getPortalid()+" invalidated.");
		return userSession.getUserid();
	}
	/*	public void disconnectSession(Integer usersessionpkey)
	{
		((UserManagerClient)onlineusermanagerclients.get(usersessionpkey)).disconnect();
	}
	public int getOnlineusercount()
	{
		return onlineusermanagerclients.size();
	}
	public Collection getOnlineusers()
	{
		ArrayList usersessions = new ArrayList();
		return usersessions;
	}
	public Collection getOnlineusers(String portalid)
	{
		ArrayList usersessions = new ArrayList();
		return usersessions;
	}*/

	/**
	 * @deprecated
	 * @param portalid
	 * @return
	 */
	public Collection<UserActionForm> getOnlineUsers(String portalid)
	{
		ArrayList<UserActionForm> onlineUsers=new ArrayList<UserActionForm>();
		for (HttpSession httpSession: httpSessions.values())
			if (httpSession.getAttribute("user")!=null&&((UserActionForm)httpSession.getAttribute("user")).getUserid()!=null&&((UserActionForm)httpSession.getAttribute("user")).getPortalid()!=null&&((UserActionForm)httpSession.getAttribute("user")).getPortalid().equals(portalid))
				onlineUsers.add((UserActionForm)httpSession.getAttribute("user"));
		return onlineUsers;
	}

	public Collection<UserSessionSBean> getOnlineUserSessions(String portalid)
	{
		ArrayList<UserSessionSBean> userSessions=new ArrayList<UserSessionSBean>();
		for (HttpSession httpSession: httpSessions.values())
			if (httpSession.getAttribute("userSession")!=null&&((UserSessionSBean)httpSession.getAttribute("userSession")).getPortalid().equals(portalid))
				userSessions.add((UserSessionSBean)httpSession.getAttribute("userSession"));
		return userSessions;
	}

	public Collection<UserSessionSBean> getOnlineAuthentifiedUserSessions(String portalid)
	{
		ArrayList<UserSessionSBean> userSessions=new ArrayList<UserSessionSBean>();
		for (HttpSession httpSession: httpSessions.values())
			if (httpSession.getAttribute("userSession")!=null&&((UserSessionSBean)httpSession.getAttribute("userSession")).getPortalid().equals(portalid)&&!((UserSessionSBean)httpSession.getAttribute("userSession")).isGuest())
				userSessions.add((UserSessionSBean)httpSession.getAttribute("userSession"));
		return userSessions;
	}

	/**
	 * @deprecated Please use getOnlineAuthtifiedUserSessions
	 * @param portalid
	 * @return
	 */
	public Collection<UserSessionSBean> getOnlineIdentifiedUserSessions(String portalid)
	{
		return getOnlineAuthentifiedUserSessions(portalid);
	}

	public Collection<UserSessionSBean> getOnlineGuestUserSessions(String portalid)
	{
		ArrayList<UserSessionSBean> userSessions=new ArrayList<UserSessionSBean>();
		for (HttpSession httpSession: httpSessions.values())
			if (httpSession.getAttribute("userSession")!=null&&((UserSessionSBean)httpSession.getAttribute("userSession")).getPortalid().equals(portalid)&&((UserSessionSBean)httpSession.getAttribute("userSession")).isGuest())
				userSessions.add((UserSessionSBean)httpSession.getAttribute("userSession"));
		return userSessions;
	}

	/*	public String[] getErrorMessage(String language, String errorcode)
	{
		return languages.getError(language,errorcode);
	}*/

	/**
	 * @deprecated Please develop a Struts Action and user com.servengine.util.File utility class
	 * Guarda el fichero incluído en la petición en el directorio indicado. Si filename no es null, guarda el fichero con ese nombre. El tamaño máximo del fichero es de 2 MBs. Devuelve un ArrayList con el resto de parámetros en el request que no son el fichero.
	 */
	public
	/*	public HashMap savefile(HttpServletRequest req, String directory, String filename) throws FileUploadException, java.io.IOException,Exception
	{	//mailbox.getContext().log("Receiving Arrachment,"+mailbox.getUser().getUserid());
		HashMap parametrostexto = new HashMap();
		DiskFileUpload upload= new DiskFileUpload();
		Iterator i = upload.parseRequest(req,100000,2000000,"/tmp").iterator();

		FileItem file = null;
		while (i.hasNext())
		{
			FileItem item = (FileItem)i.next();
			if (item.isFormField())
				parametrostexto.put(item.getFieldName(),item.getString());
			else if (item.getSize()>0)
				file=item;
		}
		if (file!=null)
		{
			File directorio = new File(directory);
			if (!directorio.exists())
				directorio.mkdir();
			file.write(new File(directorio,filename));
		}
		return parametrostexto;
	}*/
	/*
	 * Indica si ha pasado el tiempo suficiente (por defecto) para que se pueda acceder al servicio indicado por servicecategorypkey del portal portalid.
	 */
	boolean isIPAllowed(String portalid, Integer serviceCategoryId, ServletRequest request)
	{
		return serviceiplimiter.checkaccess(portalid, serviceCategoryId, request);
	}
	/*
	 * Indica si ha pasado el tiempo suficiente (indicado en segundos seconds) en para que se pueda acceder al servicio indicado por servicecategorypkey del portal portalid.
	 */

	public boolean isIPAllowed(String portalid, Integer serviceCategoryId, ServletRequest request, int seconds)
	{
		return serviceiplimiter.checkaccess(portalid, serviceCategoryId, request, seconds);
	}

	/**
	 Este método no debería ser usado más que en ocasiones especiales (creación de un portal desde un JSP de prueba)
	 */
	public
	/*	public void createportal(String portalid, String description, String language, String adminid, String adminpassword, String adminemail, String adminfirstname, String adminlastname, String adminlastname2, String portaltype) throws CreateException,java.rmi.RemoteException,IOException,FinderException
	{
		portalmanager.createPortal(portalid,null,description,language,adminid,adminpassword,adminemail,adminfirstname, adminlastname, adminlastname2);
		for (String serviceid: getPortaltypeservices(portaltype))
			portalmanager.enableservice(portalid,serviceid);
	}*/
	/*	public void sendEmail(String portalid, String from, String to, String templateid, Map substitutions) throws FinderException,javax.mail.MessagingException,RemoteException
	{
		mailRelay.send(portalid,from,to,templateid,substitutions);
	}*/

	/*	public void newComponent(String classname, boolean haspalettelink, boolean authentifiedclient) throws CreateException, RemoteException
	{
		statelessutils.newComponent(classname,haspalettelink,authentifiedclient);
	}
	public void checkportal(HttpServletRequest request) throws RemoteException
	{
		String portalid = request.getParameter("portalid");
		if (portalid==null || portalid.length()==0)
			return;
		HttpSession session = request.getSession(true);
		UserSBean user = (UserSBean)session.getAttribute("user");
		if (user==null || !user.getPortalid().equals(portalid))// || !beaninitialized)
		{
			if (user!=null)
				servletcontext.log("Cambio de portal: "+user.getPortalid()+" -> "+portalid);
			try
			{
				user = usermanager.getGuestuser(portalid);
			} catch (FinderException e)
			{
				throw new UnidentifiedUserException();
			}
			catch (NullPointerException e) { e.printStackTrace();}
			try
			{
				removeClients(session, this.getClass());
			} catch (ClassNotFoundException e)
			{
				servletcontext.log(e.getMessage(),e);
			}
			session.setAttribute("user",user);
			if (session.isNew())
			{
				servletcontext.log("Nueva sesion: "+user.getPortalid());
			}
			return;
		}
	}*/
	/*	public void setSendportalusersforemail(String email) throws FinderException,RemoteException,javax.mail.MessagingException
	{
		usermanager.sendUserswithemaillist(email);
	}*/

	/*	public FileManager getImagesfilemanager(String portalid, String serviceid)
	{
	  String pu = servletcontext.getInitParameter(serviceid+".workdir");
	  if (pu==null)
	  {
	    pu = servletcontext.getRealPath("/WEB-INF/servengine/"+serviceid+"/");
	    if (pu==null)
	      pu = "/var/lib/servengine/"+serviceid+"/";
	    if (log.isDebugEnabled()) log.debug("No "+serviceid+".workdir specified in web.xml. Defaults to "+pu);
	  }
	  return new FileManager(pu+"/"+portalid+"/images",true);
	}*/
	/*	public FileManager getServicefilemanager(String portalid, String serviceid)
	{
	  String pu = servletcontext.getInitParameter(serviceid+".workdir");
	  if (pu==null)
	  {
	    pu = servletcontext.getRealPath("/WEB-INF/servengine/"+serviceid+"/");
	    if (pu==null)
	      pu = "/var/lib/servengine/"+serviceid+"/";
	    if (log.isDebugEnabled()) log.debug("No "+serviceid+".workdir specified in web.xml. Defaults to "+pu);
	  }
	  return new FileManager(pu+"/"+portalid,true);
	}*/
	/*	public FileManager getThumbnailsfilemanager(String portalid, String serviceid)
	{
	  String pu = servletcontext.getInitParameter("images.thumbnailsdir");
	  if (pu==null)
	  {
	    pu = servletcontext.getRealPath("/")+"/thumbnails";
	    servletcontext.log("No images.thumbnailsdir specified in web.xml. Defaults to "+pu);
	  }
	  return new FileManager(pu+"/"+serviceid+"/"+portalid,true);
	}*/
	/*	public boolean hasuserpicture(String portalid, String userid) throws RemoteException
	{
		try
		{
			return hasuserpicture(portalid,usermanager.getUser(portalid,userid).getPkey());
		} catch (FinderException e)
		{
			if (log.isDebugEnabled()) log.debug("User "+userid+"@"+portalid+" doesn't exist");
			return false;
		}
	}

	public boolean hasuserpicture(String portalid, Integer userpkey)
	{
	  return new File(userpicturesdir,portalid+"/"+userpkey+".jpg").exists();
	}

	public File getUserpicturesdir()
	{
		return userpicturesdir;
	}

	public File getUserpicturesdir(String portalid)
	{
		return new File(userpicturesdir,portalid);
	}
	public String getUserpictureuri(String portalid, String userid) throws FinderException,RemoteException
	{
		Integer userpkey = usermanager.getUser(portalid,userid).getPkey();
	  String userpictureabsolutepath = new File(getUserpicturesdir(portalid),userpkey+".jpg").getAbsolutePath();
	  if (userpictureabsolutepath.indexOf(servletcontext.getRealPath("/"))!=0)
	    throw new IllegalStateException(userpictureabsolutepath+"<>"+servletcontext.getRealPath("/"));
	  return userpictureabsolutepath.substring(servletcontext.getRealPath("/").length()-1);
	}*/
	Set<Map.Entry<String, String>> getLocales()
	{
		Map<String, String> languages=new HashMap<String, String>();
		languages.put("Default", "");
		languages.put("English", "en_US");
		languages.put("Castellano", "es_ES");
		return languages.entrySet();
	}
	/*	public UserSBean getGuestuser(String portalid) throws RemoteException,FinderException
	{
		return usermanager.getGuestuser(portalid);
	}*/

	/*	public StatelessUtilsLocal getStatelessutils()
	{
		return statelessutils;
	}*/

	public Integer[] getDaysOfMonth()
	{
		return new Integer[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
	}

	public Integer[] getMonths()
	{
		return new Integer[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
	}

	public Integer[] getYears()
	{
		return getLastYears(100);
	}

	public Integer[] getLastYears(int howmany)
	{
		int year=GregorianCalendar.getInstance().get(Calendar.YEAR);
		Integer[] years=new Integer[howmany];
		for (int i=0;i<howmany;i++)
			years[i]=i+1+year-howmany;
		return years;
	}

	public boolean hasExpensiveDatum(String portalid, String id)
	{
		return expensiveDataFactory.hasExpensiveDatum(portalid, id);
	}

	public Object getExpensiveDatum(String portalid, String key)
	{
		return expensiveDataFactory.getExpensiveDatum(portalid, key);
	}

	public void setExpensiveDatum(String portalid, String key, Object datum)
	{
		expensiveDataFactory.setExpensiveDatum(portalid, key, datum);
	}

	public int getUserCount()
	{
		return (Integer)expensiveDataFactory.getExpensiveDatum(null, "userCount");
	}

	public String getServletContextName()
	{
		return servletContext.getServletContextName();
	}
	/*	public Collection<Category> getMainCategories() throws FinderException,RemoteException
	{
		return portalmanager.getRootCategories();
	}*/

	public static String getRequestURL(HttpServletRequest request)
	{
		return request.getScheme()+"://"+request.getServerName()+(request.getServerPort()==80?"":":"+request.getServerPort())+request.getContextPath();
	}

	public void checkActionsAndCleanersInContext()
	{

		Set<Component> actionsInContextClassPath=new HashSet<Component>();
		cleanersInContextClassPath=new HashMap<String, Cleaner>();
		for (String resourcePath: (Set<String>)servletContext.getResourcePaths("/WEB-INF/lib/"))
			if (resourcePath.toLowerCase().indexOf("servengine")>-1)
				try
				{
					log.info("Checking classes in "+resourcePath);
					JarInputStream jarFile=new JarInputStream(servletContext.getResourceAsStream(resourcePath));
					JarEntry jarEntry;
					while (true)
					{
						jarEntry=jarFile.getNextJarEntry();
						if (jarEntry==null)
						{
							break;
						}
						if (jarEntry.getName().endsWith(".class"))
						{
							try
							{
								Class mappingclass=Class.forName(jarEntry.getName().substring(0, jarEntry.getName().length()-6).replaceAll("/", "\\."));
								if (Class.forName("com.servengine.struts.ClientAction").isAssignableFrom(mappingclass)&&!mappingclass.isInterface()&&!java.lang.reflect.Modifier.isAbstract(mappingclass.getModifiers()))
								{
								  boolean adminServiceAction=Class.forName("com.servengine.struts.AdminServiceAction").isAssignableFrom(Class.forName(mappingclass.getName()));
									boolean unidentifiedUserAction=!adminServiceAction && Class.forName("com.servengine.struts.UnidentifiedUserAction").isAssignableFrom(Class.forName(mappingclass.getName()));
									Component action=new Component(mappingclass.getName(), unidentifiedUserAction, adminServiceAction);
									actionsInContextClassPath.add(action);
									if (log.isDebugEnabled())
										log.debug("ClientAction found: "+mappingclass.getName());
								} else if (Class.forName("com.servengine.Cleaner").isAssignableFrom(mappingclass)&&!mappingclass.isInterface()&&!java.lang.reflect.Modifier.isAbstract(mappingclass.getModifiers()))
								{
									Class[] constructorclasses=new Class[]{ Class.forName("javax.servlet.ServletContext") };
									Object[] constructorparameters=new Object[]{ servletContext };
									com.servengine.Cleaner cleaner=(com.servengine.Cleaner)(Class.forName(mappingclass.getName()).getConstructor(constructorclasses).newInstance(constructorparameters));
									cleanersInContextClassPath.put(mappingclass.getName(), cleaner);
									if (log.isDebugEnabled())
										log.debug("Cleaner found: "+mappingclass.getName());
								}
							} catch (NoClassDefFoundError e)
							{
								log.warn(jarEntry.getName()+": "+e+": "+e.getMessage());
							} catch (ClassNotFoundException e)
							{
								log.warn(jarEntry.getName()+": "+e+": "+e.getMessage());
							} catch (Throwable e)
							{
								if (log.isDebugEnabled())
									log.debug(jarEntry.getName()+": "+e.getMessage(), e);
								else
									log.warn(jarEntry.getName()+": "+e.getMessage());
							}
						}
					}
				} catch (IOException e)
				{
					log.error(e.getMessage(), e);
				}
		syncActionsInClientClassPath(actionsInContextClassPath);

		log.info(actionsInContextClassPath.size()+" Actions");
		log.info(cleanersInContextClassPath.size()+" Cleaners");
	}

	private void syncActionsInClientClassPath(Set<Component> actions)
	{
		HashMap<String, Component> systemActions = new HashMap<String, Component>(); //No puedo quitar Actions del puto Set. No lo comprueba con equals. ¿?¿?
		for (Component action: portalmanager.getAllActions())
			systemActions.put(action.getClassName(), action);
		for (Component action: actions)
		{
			Component aux = portalmanager.getAction(action.getClassName());
			if (aux==null)
			{
				log.warn("Adding action in client classpath to database: "+action.getClassName());
				portalmanager.persist(action);
			} else // TODO comparar el de la base de datos con el del classpath
			{
				if (action.isAdmin()!=aux.isAdmin())
					log.warn("Action "+action.getClassName()+" is "+(!aux.isAdmin()?"not ":"")+"adminServiceAction in server");
			  if (action.isGuest()!=aux.isGuest())
			    log.warn("Action "+action.getClassName()+" is "+(!aux.isGuest()?"not ":"")+"unidentifiedUserAction in server");
			}
			//  entityManager.merge(action);
			if (systemActions.remove(action.getClassName())==null)
				log.warn("Action "+action.getClassName()+" could not be removed from database Set");
		}
		for (Component action: systemActions.values())
		{
			log.warn("Component not present in client classpath: "+action.getClassName());
			//      action.remove(); //TODO No activar esto. En tuportal.com puede causar estragos
		}

		//    log.info(nonSystemServiceNames.size()+" non system services in client classpath");
	}

	/*	public Component getAction(String className)
	{
		if (!actionsInContextClassPath.containsKey(className))
			log.error("Action "+className+" not in webapp /lib dir");
		return actionsInContextClassPath.get(className);
	}*/

	public String getGenericPortalid()
	{
		return genericportalid;
	}

	/**
	 * @deprecated Please usee getResourceAsString
	 * @param user
	 * @param request
	 * @param response
	 * @param templatePath
	 * @return
	 * @throws ServletException
	 * @throws IOException
	 */
	public String getMailTemplate(User user, HttpServletRequest request, HttpServletResponse response, String templatePath) throws ServletException, IOException
	{
		return getResourceAsString(user, request, response, templatePath);
	}

	/**
	 * Important; JSP resource must include a small scriptlet doing out.flush()
	 * @param user
	 * @param request
	 * @param response
	 * @param path
	 * @return
	 * @throws ServletException
	 * @throws IOException
	 */
	public String getResourceAsString(User user, HttpServletRequest request, HttpServletResponse response, String path) throws ServletException, IOException
	{
		request.setAttribute("user", user);
		try
		{
			ByteArrayOutputStream out=new ByteArrayOutputStream();
			RequestDispatcher dispatcher=request.getRequestDispatcher(path);
			RedirectingServletResponse dummyResponse=new RedirectingServletResponse(response, out);
			dispatcher.include(request, dummyResponse);
			//		  dummyResponse.flushBuffer(); // TODO Importante: Se debe poner el flush en el jSP (!!!!)
			//		  out.flush();
			return out.toString();

			/*BufferedReader reader = new BufferedReader(new InputStreamReader(servletcontext.getResourceAsStream("/WEB-INF/mailtemplates/"+templatePath)));
		String line = null;
		String html = new String();
		while ((line=reader.readLine())!=null)
			html+=line+"\n";
	  return html;*/
		} catch (NullPointerException e)
		{
			return "<p>No "+path+" template</p>"; // TODO Internacionalizar este mensaje.
		}
	}
	/*			 public UserTransaction getUserTransaction()
			 {
			   try
			   {
			     Object obj = new InitialContext().lookup("java:comp/UserTransaction");
			     if (!(obj instanceof javax.transaction.UserTransaction))
			     {
			       log.error(obj.getClass()+" is not instance of javax.transaction.UserTransaction, but "+obj.getClass().getInterfaces()[0]+", returning null.");
			       return null;
			     }
			     if (log.isDebugEnabled()) log.debug("Transaction: "+obj.getClass());
			     javax.transaction.UserTransaction tx = (javax.transaction.UserTransaction)obj;
			     if (tx.getStatus()==Status.STATUS_NO_TRANSACTION)
			       try
			       {
			          tx.begin();
			       } catch (Throwable e)
			       {
			         log.error(e.getMessage(),e);
			       }
			    return tx;
			   } catch (Exception e)
			   {
			     throw new IllegalStateException(e.getMessage(),e);
			   }
			 }*/

	/*	public UserSession getGuestUserSession(String portalid)
	{
		return new UserSession(guestUsers.get(portalid));
	}*/

	public UserSessionSBean getUserSessionSBean(UserSession userSession)
	{
		return new UserSessionSBean(userSession);
	}

	public static String getMessageDigest(String input)
	{
		String[] inputs=new String[2];
		inputs[0]=input;
		return getMessageDigest(inputs);
	}

	public static String getMessageDigest(String[] inputs)
	{
		if (inputs.length==0)
			return null;
		try
		{
			MessageDigest sha=MessageDigest.getInstance("SHA-1");
			//for(int n=0;n<values.length;n++)
			for (String input: inputs)
				sha.update(input.getBytes());
			byte[] hash=sha.digest();
			String CPass=new String();
			int h=0;
			String s=new String();
			for (int i=0;i<20;i++)
			{
				h=hash[i]; // Convertir de byte a int
				if (h<0)
					h+=256; // Si son valores negativos, pueden haber problemas de conversi?n.
				s=Integer.toHexString(h); // Devuelve el valor hexadecimal como un String
				if (s.length()<2)
					CPass=CPass.concat("0"); // A?ade un 0 si es necesario
				CPass=CPass.concat(s); // A?ade la conversi?n a la cadena ya existente
			}
			CPass=CPass.toUpperCase(); // Convierte la cadena generada a Mayusculas.
			return CPass;
		} catch (NoSuchAlgorithmException e)
		{
			throw new IllegalStateException(e.getMessage());
		}
	}
	//Este método no se usa. Se deja aquí para implementaciones como PortalNZ y Tuportal.com
	//Cuidado, esto carga el tema.

	protected Map<String, String> getColors(Portal portal)
	{
		String colorsProperty=portal.getProperty(PORTAL_COLORS_PROPERTY_NAME);
		if (colorsProperty==null)
			colorsProperty=getPortalmanager().getPortal(getGenericPortalid()).getProperty(PORTAL_COLORS_PROPERTY_NAME);
		if (colorsProperty==null)
		{
			log.warn("No portal.colors property in generic portal: "+getGenericPortalid()+". Returning null.");
			return null;
		}
		Map<String, String> colorMap=new HashMap<String, String>();
		String[] colors=colorsProperty.split(",");
		colorMap.put("textcolor", colors[0]);
		colorMap.put("htextcolor", colors[1]);
		colorMap.put("textcolor2", colors[2]);
		colorMap.put("htextcolor2", colors[3]);
		colorMap.put("bgcolor", colors[4]);
		colorMap.put("pbgcolor", colors[5]);
		colorMap.put("bgcolor2", colors[6]);
		colorMap.put("pbgcolor2", colors[7]);
		return colorMap;
	}

	//Este método no se usa. Se deja aquí para implementaciones como PortalNZ y Tuportal.com

	protected String getCssURL(Portal portal)
	{
		String cssURL=portal.getProperty(PORTAL_CSSURL_PROPERTY_NAME);
		if (cssURL==null)
			cssURL=getPortalmanager().getPortal(getGenericPortalid()).getProperty(PORTAL_CSSURL_PROPERTY_NAME);
		if (cssURL==null)
			log.warn("No portal.cssURL property in generic portal: "+getGenericPortalid()+". Returning null.");
		return cssURL;
	}

}
